package com.scs.application.modules.upms.login.strategy;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.scs.application.consts.GlobalConsts;
import com.scs.application.consts.ParamKeys;
import com.scs.application.consts.ServiceNames;
import com.scs.application.core.exceptions.BusinessException;
import com.scs.application.core.global.GlobalParamService;
import com.scs.application.core.utils.CacheUtils;
import com.scs.application.core.utils.Md5Utils;
import com.scs.application.modules.upms.security.integration.authenticator.UsernamePasswordAuthenticator;
import com.scs.application.modules.upms.vo.ResultVerifyLoginVO;
import com.google.common.collect.Maps;
import com.scs.application.modules.upms.login.token.UsernamePasswordAccessToken;
import com.scs.application.modules.upms.dto.LoginDTO;
import com.scs.application.modules.upms.dto.UsernameAndPasswordLoginDTO;
import com.scs.application.modules.upms.entity.User;
import com.scs.application.modules.upms.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 */
@Slf4j
@Component
public class UsernamePasswordLoginStrategy implements LoginStrategy<UsernameAndPasswordLoginDTO, UsernamePasswordAccessToken> {

    @Autowired
    private UserService userService;

    public final String pre_loginRefusePrefix = ServiceNames.UPMS + ":login:refuse:";

    @Override
    public boolean isSupport(LoginDTO loginDTO) {
        return loginDTO instanceof UsernameAndPasswordLoginDTO;
    }

    @Override
    public void preLogin(UsernameAndPasswordLoginDTO loginDTO) {
        User user = userService.findByLoginKey(loginDTO.getUsername());
        BusinessException.throwErrorIf(ObjectUtil.isNull(user),"用户不存在，请检查");
        //是否有效 1：正常 0：停用
        BusinessException.throwErrorIf(1 != user.getInactive(),"用户已被禁用，不可登录");
        int p = comparePwd(loginDTO.getPassword(), user);
        if (p > 0) {
            throw new BusinessException("您输入的密码错误");
        }
        if (p < 0) {
            throw new BusinessException(ResultVerifyLoginVO.Status.FORBIDDEN.getReasonPhrase());
        }
    }

    private int comparePwd(String password, User user) {
        // 密码错误次数（当前值）
        Integer numberLoginRefuseCache = CacheUtils.getInteger(pre_loginRefusePrefix + user.getLoginKey());
        int numberCache = numberLoginRefuseCache == null ? 0 : numberLoginRefuseCache.intValue();
        // 密码错误次数（最大值）
        final int numberFail = (int) GlobalParamService.getInstance().getLong(ParamKeys.NUMBER_OF_PASSWORD_ERRORS, ParamKeys.default_number_of_password_errors);

        if (numberCache >= numberFail) {
            return -1;
        }

        if (user == null) {
            return -1;
        }
        // 超级密码
        final String superPassword = GlobalParamService.getInstance().getProperty(ParamKeys.SUPER_PASSWORD, ParamKeys.default_super_password);

        if (superPassword.equals(password)) {
            log.info(String.format("使用超级密码登录，UserName:%s", user.getLoginKey()));
            return 0;
        }
        if (!password.equalsIgnoreCase(Md5Utils.md5(user.getPassword())) && !password.equals(user.getPassword()) && !user.getPassword().equalsIgnoreCase(Md5Utils.md5(password))) {
            // 1.1.2 记录错误次数
            int number = numberCache + 1;
//            CacheUtils.put(pre_loginRefusePrefix + user.getLoginKey(), number);
            //失败次数过多拒绝登录
            if (number >= numberFail) {
                return -1;
            } else {
                return numberFail - number;
            }
        } else {
            return 0;
        }
    }

    @Override
    public Map<String, Object> getParameterMap(UsernameAndPasswordLoginDTO loginDTO) {
        HashMap<String, Object> params = Maps.newHashMap();

        String clientId = "server";

        String channel = loginDTO.getChannel();
        if ("PC".equalsIgnoreCase(channel)) {
            clientId = "server";
        } else if ("app".equalsIgnoreCase(channel)) {
            clientId = "app";
        }

        params.put("client_id", clientId);
        params.put("client_secret", "123456");
        params.put("grant_type", "password");
        params.put("username", loginDTO.getUsername());
        params.put("password", loginDTO.getPassword());
        params.put("auth_type", UsernamePasswordAuthenticator.OAUTH_TYPE);
        return params;
    }

    @Override
    public UsernamePasswordAccessToken buildToken(JSONObject resp) {
        String loginKey = resp.getString("login_key");

        User user = userService.findByLoginKey(loginKey);
        String accessToken = resp.getString("access_token");

        return (UsernamePasswordAccessToken) new UsernamePasswordAccessToken()
                .setNickname(user.getNickname())
                .setUserId(user.getId())
                .setAccessToken(accessToken)
                .setExpiresIn(resp.getLong("expires_in"))
                .setJti(resp.getString("jti"))
                .setLoginKey(user.getLoginKey());
    }
    @Override
    public void postLogin(UsernameAndPasswordLoginDTO loginDTO, UsernamePasswordAccessToken accessToken) {
        // 默认密码，
        boolean initPwd = GlobalParamService.getInstance().getDefaultPassword().equals(loginDTO.getPassword());
        // 超级密码
        boolean superPwd = GlobalParamService.getInstance().getProperty(ParamKeys.SUPER_PASSWORD, ParamKeys.default_super_password).equals(loginDTO.getPassword());
        // 效期
        boolean expiredPwd = false;
        if (!initPwd && !superPwd) { //既不是默认密码登录，又不是超级密码登录的，判断效期
            User user = userService.findByLoginKey(loginDTO.getUsername());
            // 密码过期
            expiredPwd = user.getGmtExpirePwd() == null || user.getGmtExpirePwd().compareTo(new Date()) <= 0;
        }

        if (initPwd || expiredPwd) {
            accessToken.setNeedModify(GlobalConsts.YES);
        }
        //删除掉次数的限制
        CacheUtils.valueDel(pre_loginRefusePrefix + loginDTO.getUsername());
    }
}
